/*
Visual Clip Tool
	by TGiFallen
	Credits to Ralle105 of facepunch
*/

TOOL.Category		= "Construction"
TOOL.Name			= "#Visual Clip"
TOOL.Command		= nil
TOOL.ConfigName		= ""

TOOL.ClientConVar["distance"] = "1"
TOOL.ClientConVar["x"] = "0"
TOOL.ClientConVar["y"] = "0"
TOOL.ClientConVar["z"] = "1"
TOOL.ClientConVar["inside"] = "0"


local Clipped = {}
if CLIENT then
	language.Add( "Tool_visual_name", "Visual Clip Tool" )
	language.Add( "Tool_visual_desc", "Visual Clip Models" )
	language.Add( "Tool_visual_0", "Primary: Start Clipping Selection (Do BEFORE you parent) 	Reload: Remove Clips" )
	language.Add( "Tool_visual_1", "Now click on a second spot" )
	language.Add( "Tool_visual_2", "Now select the side of the prop you want to keep	Secondary: Clip prop" )

else
	hook.Add("PlayerInitialSpawn" , "VisualClip.SendClips" , function( ply )
		timer.Simple(3,function()
			for i = 1 , #Clipped do
				local ent = Clipped[i]
				SendClip( ply , ent)
			end
		end)
	end)
end

local function SendClip( ply , Entity )
	if CLIENT then return end
	local Data = Entity.ClipData
	if ply then
		if !Entity.EntityMods or !Entity.EntityMods.clips then return end
		for k , v in pairs(Entity.EntityMods.clips ) do
			umsg.Start("visual_clip_newclip")
				umsg.Entity(Entity)
				umsg.Float(v.n.p)
				umsg.Float(v.n.y)
				umsg.Float(v.n.r)
				umsg.Float(v.d)
				umsg.Bool(v.inside)
			umsg.End()
		end
		return
	end
	for k , v in pairs(Data) do
		umsg.Start("visual_clip_newclip")
			umsg.Entity(Entity)
			umsg.Float(v.n.p)
			umsg.Float(v.n.y)
			umsg.Float(v.n.r)
			umsg.Float(v.d)
			umsg.Bool(v.inside)
		umsg.End()
	end		
end
duplicator.RegisterEntityModifier( "clips", function( p , Entity , data)
	if !Entity:IsValid() then return end
	Entity.ClipData = data
	timer.Simple(0, SendClip , nil , Entity )
	duplicator.StoreEntityModifier( Entity, "clips", Entity.ClipData )
end)

local spots = {}
function TOOL:RightClick( trace )
	local ent = trace.Entity
	if self:GetStage() == 2 then
		self.toggle = !self.toggle
		print(self:GetStage())

		local norm = (spots[1] - spots[2]):GetNormalized()
		local ang = norm:Angle()
		local pos = ent:GetPos()
		local center = (spots[1] + spots[2]) / 2

		if self.toggle then
			ang:RotateAroundAxis(ang:Right() , -90 )
		else
			ang:RotateAroundAxis(ang:Right() , 90 )
		end
		local Normal = -ang:Forward()
		local LinePoint1 = spots[1]
		local LinePoint2 = spots[1] + ang:Forward()
		local dist = (Normal:Dot(pos-LinePoint1))/(Normal:Dot(LinePoint2-LinePoint1))
		
		umsg.Start("visual_clip_data")
			local ang = ent:WorldToLocalAngles(Normal:Angle())
			umsg.Float(ang.p)
			umsg.Float(ang.y)
			umsg.Float(ang.r)
			umsg.Float(dist)
		umsg.End()

	end
	return true;
end
//TOOL.toggle = true
function TOOL:LeftClick( trace )
	local ent = trace.Entity
	if CLIENT then return true end
	if !ent:IsValid() or ent:IsWorld() or ent:GetClass() != "prop_physics" then return false end
	local ent = trace.Entity
	local pos = trace.HitPos
	local stage = self:GetStage()
	if stage < 2 then
		spots[ stage + 1 ] = pos
		
		self:SetStage( stage + 1)
		if stage == 1 then
			self:RightClick(trace)
		end
		return
	end
	if stage == 2 then
		
		self:SetStage(0)
				
		ent.ClipData = ent.ClipData or {}
		if #ent.ClipData > 2 then
			self:GetOwner():PrintMessage(HUD_PRINTCENTER , "Only 3 clip planes per entity allowed!")
			return
		end

		table.insert(ent.ClipData , {
			n = spots.ang,
			d = spots.dist,
			inside = tobool( self:GetClientInfo("inside") or false ) 
		})
		SendClip( nil , ent )
		duplicator.StoreEntityModifier( ent , "clips", ent.ClipData )
		table.insert(Clipped , ent)
	end
	return true
end

function TOOL:Reload( trace )
	if CLIENT then return true end
	local ent = trace.Entity
	if !ent:IsValid() or ent:IsWorld() then return end
	ent.EntityMods = ent.EntityMods or {}
	ent.EntityMods.clips = {}
	ent.ClipData = {}
	umsg.Start("visual_clip_reset")
		umsg.Entity(ent)
	umsg.End()
	return true
end


if CLIENT then
	function TOOL.BuildCPanel( cp )
		cp:AddControl( "Header", { Text = "#Tool_visual_name", Description	= "#Tool_visual_desc" }  )

		cp:AddControl("Slider", { Label = "Distance", Type = "int", Min = "-100", Max = "100", Command = "visual_distance" } )
		cp:AddControl("Slider", { Label = "Pitch", Type = "int", Min = "-180", Max = "180", Command = "visual_p" } )
		cp:AddControl("Slider", { Label = "Yaw", Type = "int", Min = "-180", Max = "180", Command = "visual_y" } )
		cp:AddControl("Button", {Label = "Reset",Command = "visual_reset"})	
		cp:AddControl("CheckBox", {Label = "Draw the inside of the prop" , Description = "Ticking this will draw the inside of the prop (so you can't see out of it)" , Command = "visual_inside"} )

	end
	local x, y , z , d = 0 , 0 , 0 , 0
	concommand.Add("visual_reset",function()
		RunConsoleCommand("visual_x",0)
		RunConsoleCommand("visual_y",0)
		RunConsoleCommand("visual_z",1)
		RunConsoleCommand("visual_distance",0)
	end)

	cvars.AddChangeCallback("visual_x",function(_,_,new)
		p = tonumber(new) or 0		
	end)
	cvars.AddChangeCallback("visual_y",function(_,_,new)
		y = tonumber(new) or 0		
	end)
	cvars.AddChangeCallback("visual_z",function(_,_,new)
		y = tonumber(new) or 0		
	end)
	cvars.AddChangeCallback("visual_distance",function(_,_,new)
		d = tonumber(new) or 0		
	end)
	local halfmodel1 = ClientsideModel("error.mdl")
	halfmodel1:SetNoDraw(true)

	local norm , d = Vector(0,0,1) , 0 
	local function ClipData( um )
		norm = Angle(um:ReadFloat() , um:ReadFloat() , um:ReadFloat())
		RunConsoleCommand("visual_distance",um:ReadFloat())
	end
	usermessage.Hook("visual_clip_data" , ClipData)

	local function drawpreview()
		--[[
		if plane.out then
			local ang = plane.norm:Angle()
			local pos = plane.pos
		 
			ang:RotateAroundAxis( ang:Forward(), 90 )
			ang:RotateAroundAxis( ang:Right(), 90 )
		 
			cam.Start3D2D( pos, ang, 0.25 )
				draw.DrawText( "test", "CV20", 2, 2, Color( 255, 255, 255, 255 ), TEXT_ALIGN_CENTER )
			cam.End3D2D()
		end
		--]]

		local e = LocalPlayer():GetEyeTraceNoCursor().Entity
		if !e:IsValid() or e:IsWorld() or !(LocalPlayer():GetActiveWeapon():GetClass() == "gmod_tool" and GetConVarString("gmod_toolmode") == "visual") then return end

		local e_model = e:GetModel()
		if !halfmodel1.model != e_model then
			halfmodel1:SetModel( e_model )
			halfmodel1.model = e_model
		end
		local e_pos = e:GetPos()
		local e_ang = e:GetAngles()
		
		halfmodel1:SetPos(e_pos)
		halfmodel1:SetAngles(e_ang)
		
		//local n = Angle(p,y,0):Forward()*-1
		//n:Rotate(e_ang)
		//norm = norm or Vector(0,0,1)
		local n = e:LocalToWorldAngles(norm):Forward()

		local pos = e_pos-n*d


		halfmodel1:SetModelScale(Vector()*1.01)
		local size = e:OBBMaxs() - e:OBBMins()
		local zoffset = -((size * 1.01) - size) / 200
		local offset = Vector( zoffset.x , zoffset.y , zoffset.z )
		render.EnableClipping(true)
							
		halfmodel1:SetRenderOrigin(e_pos + offset)
		render.SetColorModulation(1000,0,0)			
		render.PushCustomClipPlane(n,n:Dot(pos))
			halfmodel1:DrawModel()
			render.CullMode(MATERIAL_CULLMODE_CW)
				halfmodel1:DrawModel()
			render.CullMode(MATERIAL_CULLMODE_CCW)
		render.PopCustomClipPlane()
		render.SetColorModulation(1,1,1)		
		render.EnableClipping(false)
	end
	hook.Add("PostDrawOpaqueRenderables" , "VisualClip.Preview" , drawpreview )

end




